// 1.MQTT客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"

#define ADDRESS "thirdparty.mqtt.yoplore.com" // 服务器的IP地址
#define CLIENTID "client01"                   // 发布者的姓名(唯一的，如果发布者和订阅者用同一个姓名，就会出现顶号的现象)
#define TOPIC1 "MQTT topic/topic1"            // 订阅主题
#define TOPIC2 "MQTT topic/topic2"            // 订阅主题
#define QOS 1                                 // 服务登记（0.最多一次，1.最少一次，2.确保一次）
#define TIMEOUT 10000L                        // 响应时间

// 定义一个传递令牌
volatile MQTTClient_deliveryToken deliveredtoken;

// 令牌交付回调函数，当消息成功交付给 MQTT 服务器时调用
/**
    context：用户自定义的上下文指针，此处未使用
    dt：消息交付的令牌
*/
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

// 接受订阅信息的回调函数，当接收到订阅主题的消息时调用
/**
    context：用户自定义的上下文指针，此处未使用
    topicName：接收到消息的主题名称
    topicLen：主题名称的长度
    message：接收到的 MQTT 消息结构体指针
*/
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    int i;
    char *payloadptr;
    printf("Message arrived\n");
    printf("topic: %s\n", topicName);
    printf("message: ");
    payloadptr = message->payload;
    for (i = 0; i < message->payloadlen; i++)
    {
        putchar(*payloadptr);
        payloadptr++;
    }
    putchar('\n');
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}
// 断开链接的回调函数
void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("cause: %s\n", cause);
}

int main(int argc, char *argv[])
{
    printf("\nCreating MQTTClient\n");
    // 消息缓冲区
    char buf[1024];
    // 1、定义一个MQTT客户端结构体指针
    MQTTClient client;
    // 2、创建一个MQTT客户端
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_create(&client, ADDRESS, CLIENTID,
                      MQTTCLIENT_PERSISTENCE_NONE, NULL);

    conn_opts.keepAliveInterval = 20; // 连接保活时间
    conn_opts.cleansession = 1;       // 设置是否清除会话，1为清除

    // 定义一个 MQTT 消息结构体，用于存储要发布的消息
    MQTTClient_message publish_msg = MQTTClient_message_initializer;
    // 令牌token
    MQTTClient_deliveryToken token;

    // 设置回调
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    // 链接
    int rc = MQTTClient_connect(client, &conn_opts);
    if (rc != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        return EXIT_FAILURE;
    }
    // 订阅多个主题
    rc = MQTTClient_subscribe(client, TOPIC1, QOS);
    if (rc != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to subscribe to %s, return code %d\n", TOPIC1, rc);
        return EXIT_FAILURE;
    }
    rc = MQTTClient_subscribe(client, TOPIC2, QOS);
    if (rc != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to subscribe to %s, return code %d\n", TOPIC2, rc);
        return EXIT_FAILURE;
    }
    // 用户退出
    char ch;
    while (1)
    {
        // 发送信息
        printf("请输入要发布的内容（输入 'q' 或 'Q' 退出）：\n");
        if (fgets(buf, sizeof(buf), stdin) == NULL)
        {
            printf("读取输入失败\n");
            continue;
        }
        // 去除换行符(fgets会将换行符一并读取)
        size_t len = strlen(buf);
        if (len > 0 && buf[len - 1] == '\n')
        {
            buf[len - 1] = '\0';
        }
        // 检查是否退出
        if (buf[0] == 'q' || buf[0] == 'Q')
        {
            break;
        }
        publish_msg.payload = (void *)buf;
        publish_msg.payloadlen = strlen(buf);
        rc = MQTTClient_publishMessage(client, TOPIC2, &publish_msg, &token); // 用于将消息发布到指定的主题
        if (rc != MQTTCLIENT_SUCCESS)
        {
            printf("Failed to publish message, return code %d\n", rc);
            continue;
        }
        rc = MQTTClient_waitForCompletion(client, token, 1000); // 用于等待指定的消息交付完成
        if (rc != MQTTCLIENT_SUCCESS)
        {
            printf("Failed to wait for message completion, return code %d\n", rc);
            continue;
        }
        printf("buf中的内容: %s\n", buf);
    }

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    printf("\nExiting\n");
    return 0;
}

// 2.RTOS测试
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>

// 低优先级线程函数
void *low_priority_thread(void *arg)
{
    int i;
    for (i = 0; i < 5; i++)
    {
        printf("Low priority thread is running: %d\n", i);
    }
    return NULL;
}

// 高优先级线程函数
void *high_priority_thread(void *arg)
{
    int i;
    for (i = 0; i < 5; i++)
    {
        printf("High priority thread is running: %d\n", i);
    }
    return NULL;
}

int main()
{
    pthread_t low_thread, high_thread;
    struct sched_param low_param, high_param;
    pthread_attr_t low_attr, high_attr;

    // 初始化低优先级线程属性
    pthread_attr_init(&low_attr);
    // 设置低优先级线程调度策略为 SCHED_FIFO
    pthread_attr_setschedpolicy(&low_attr, SCHED_FIFO);
    low_param.sched_priority = sched_get_priority_min(SCHED_FIFO);
    // 设置低优先级线程优先级
    pthread_attr_setschedparam(&low_attr, &low_param);

    // 初始化高优先级线程属性
    pthread_attr_init(&high_attr);
    // 设置高优先级线程调度策略为 SCHED_FIFO
    pthread_attr_setschedpolicy(&high_attr, SCHED_FIFO);
    high_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    // 设置高优先级线程优先级
    pthread_attr_setschedparam(&high_attr, &high_param);

    // 创建高优先级线程
    if (pthread_create(&high_thread, &high_attr, high_priority_thread, NULL) != 0)
    {
        perror("pthread_create (high)");
        return 1;
    }

    // 创建低优先级线程
    if (pthread_create(&low_thread, &low_attr, low_priority_thread, NULL) != 0)
    {
        perror("pthread_create (low)");
        return 1;
    }

    // 等待高优先级线程结束
    if (pthread_join(high_thread, NULL) != 0)
    {
        perror("pthread_join (high)");
        return 1;
    }

    // 等待低优先级线程结束
    if (pthread_join(low_thread, NULL) != 0)
    {
        perror("pthread_join (low)");
        return 1;
    }

    return 0;
}